using System;
using System.ComponentModel;
using System.IO;
using System.Text.RegularExpressions;

using Supremacy.Annotations;
using Supremacy.Client;
using Supremacy.Entities;
using Supremacy.Resources;
using Supremacy.Text;
using Supremacy.Universe;

using SupremacyEditor.RacesModule;

using System.Linq;

namespace SupremacyEditor
{
    [EditorType(typeof(RaceEditor))]
    public class RacePresentationModel : EditorItemBase<Race>, IRacePresentationModel
    {
        private readonly IResourceManagerService _resourceManagerService;
        private readonly ITextDatabaseEntry<IRaceTextDatabaseEntry> _text;

        // ReSharper disable UnaccessedField.Local
        private readonly DelegatingWeakEventListener<EventArgs> _textChangedHandler;
        // ReSharper restore UnaccessedField.Local

        public RacePresentationModel(
            [NotNull] IEditorController controller,
            [NotNull] IResourceManagerService resourceManagerService,
            [NotNull] Race race)
            : base(race)
        {
            if (controller == null)
                throw new ArgumentNullException("controller");
            if (resourceManagerService == null)
                throw new ArgumentNullException("resourceManagerService");

            _resourceManagerService = resourceManagerService;

            RegisterAccessor(() => this.Key, o => o.Key, (o, v) => o.Key = v);
            RegisterAccessor(() => this.ImagePath, o => o.ImagePath, UpdateImage);
            RegisterAccessor(() => this.HomePlanetType, o => o.HomePlanetType, (o, v) => o.HomePlanetType = v);

            var raceKey = race.Key;

            var raceTextTable = controller.GameData.TextDatabase.GetTable<IRaceTextDatabaseEntry>();
            if (!raceTextTable.TryGetEntry(raceKey, out _text))
                _text = raceTextTable.CreateEntry(raceKey);

            _textChangedHandler = new DelegatingWeakEventListener<EventArgs>((s, e) => OnPropertyChanged("Header"));

            GenericWeakEventManager<EventArgs>.AddListener(
                _text,
                TypeDescriptor.GetEvents(_text)["Changed"],
                _textChangedHandler);

            this.PropertyChanging += delegate(object sender, PropertyChangingEventArgs e)
                                     {
                                         if (Equals(e.PropertyName, "PluralName"))
                                             OnPropertyChanging("Header");
                                     };

            this.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
                                    {
                                        if (Equals(e.PropertyName, "PluralName"))
                                            OnPropertyChanged("Header");
                                    };
        }

        private void OnTextChanged(object sender, EventArgs e)
        {
            OnChanged();
        }

        private void UpdateImage(Race race, string imagePath)
        {
            var fileName = Path.GetFileNameWithoutExtension(imagePath);
            var raceName = Regex.Replace(race.Key.ToLowerInvariant(), "[^_a-z]", String.Empty);
            if (!String.Equals(raceName, fileName, StringComparison.OrdinalIgnoreCase))
                fileName = Path.ChangeExtension(fileName, Path.GetExtension(imagePath));
            var desiredPath = Path.Combine(
                _resourceManagerService.GetResourcePath("resources:images:races"),
                fileName);
            var relativeSourcePath = _resourceManagerService.GetResourcePath(imagePath);
            if (String.Equals(relativeSourcePath, desiredPath))
                return;
            OnPropertyChanging("ImagePath");
            File.Copy(imagePath, desiredPath, true);
            OnPropertyChanged("ImagePath");
        }

        public override string Header
        {
            get
            {
                var displayText = this.Text.GetDisplayEntry();
                if (displayText != null)
                    return displayText.PluralName;
                return this.Key;
            }
        }

        public string Key
        {
            get { return GetValue(() => this.Key); }
            set { SetValue(() => this.Key, value); }
        }

        public ITextDatabaseEntry<IRaceTextDatabaseEntry> Text { get { return _text; } }

        [TypeConverter(typeof(EditorImageSourceConverter))]
        public string ImagePath
        {
            get { return GetValue(() => this.ImagePath); }
            set { SetValue(() => this.ImagePath, value); }
        }

        public PlanetType HomePlanetType
        {
            get { return GetValue(() => this.HomePlanetType); }
            set { SetValue(() => this.HomePlanetType, value); }
        }

        protected override bool IsChangedOverride()
        {
            return this.Text.IsChanged;
        }

        protected override void OnBeginEdit()
        {
            base.OnBeginEdit();
            this.Text.BeginEdit();
        }

        protected override void OnCancelEdit()
        {
            base.OnCancelEdit();
            this.Text.CancelEdit();
        }

        protected override void CommitChangesOverride(CommitChangesOperation commit)
        {
            base.CommitChangesOverride(commit);
            this.Text.EndEdit();
        }
    }
}